#pragma once

#include <variant>

namespace header
{
namespace ini
{

class IniValue
{
public:
    IniValue() { _val = "null"; }
    IniValue(bool b) { _val = b; }
    IniValue(int i) { _val = i; }
    IniValue(double d) { _val = d; }
    IniValue(const char* s) { _val = std::string{s}; }
    IniValue(const std::string& s) { _val = s; }
    ~IniValue() = default;

public:
    bool to_bool() const
    {
        if (!std::get_if<bool>(&_val)) throw std::bad_cast();
        return std::get<bool>(_val);
    }

    int to_int() const
    {
        if (!std::get_if<int>(&_val)) throw std::bad_cast();
        return std::get<int>(_val);
    }

    double to_double() const
    {
        if (!std::get_if<double>(&_val)) throw std::bad_cast();
        return std::get<double>(_val);
    }

    std::string to_string() const
    {
        if (!std::get_if<std::string>(&_val)) throw std::bad_cast();
        return std::get<std::string>(_val);
    }

    std::string str() const
    {
        if (std::get_if<bool>(&_val)) {
            if (std::get<bool>(_val)) return "true";
            return "false";
        }
        else if (std::get_if<int>(&_val)) 
            return std::to_string(std::get<int>(_val));
        else if (std::get_if<double>(&_val)) 
            return std::to_string(std::get<double>(_val));
        else if (std::get_if<std::string>(&_val))
            return std::get<std::string>(_val);
        else throw std::bad_cast();
        return "";
    }

public:
    IniValue& operator=(bool b) 
    {
        _val = b;
        return *this;
    }

    IniValue& operator=(int i) 
    {
        _val = i;
        return *this;
    }
    
    IniValue& operator=(double d) 
    {
        _val = d;
        return *this;
    }

    IniValue& operator=(const char* s) 
    {
        _val = std::string{s};
        return *this;
    }
    
    IniValue& operator=(const std::string& s) 
    {
        _val = s;
        return *this;
    }

private:
    std::variant<bool, int, double, std::string> _val;
};

}   // namespace ini
}   // namespace header
